package game.Engine.Entity;

import game.MainController;
import game.Engine.Entity.Magic.MagicType;
import game.display.Animation;
import game.display.Images;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.Random;

public class Alien extends Creature {
	private MagicType type;

	private static Random r = new Random();

	private static final double JUMP_SPEED = -8f;
	private static final long SLEEP_TIME = 30000000000L;

	private static Animation[] moving, attacking, dying;
	static {
	   moving = new Animation[] { Images.ALIENMOVING.image(),
            Images.ALIENMOVING_RED.image(),
            Images.ALIENMOVING_GREEN.image(),
            Images.ALIENMOVING_BLUE.image() };
      attacking = new Animation[] { Images.ALIENATTACKING.image(),
            Images.ALIENATTACKING_RED.image(),
            Images.ALIENATTACKING_GREEN.image(),
            Images.ALIENATTACKING_BLUE.image() };
      dying = new Animation[] { Images.ALIENDYING.image(),
            Images.ALIENDYING_RED.image(), Images.ALIENDYING_GREEN.image(),
            Images.ALIENDYING_BLUE.image() };
	}
	private long respawnCountForTimer;

	private transient int points;
	private transient long timeToBeat = 1000000;
	
	public transient long lastCast;
	private transient Point2D.Double myLoc;

	public Alien(Point p, int i) {
		super(0, 0, null);
		points = 100;
		this.x = (double) p.getX();
		this.y = (double) p.getY();
		this.state = State.SLEEPING;
		this.gi = Images.ALIENMOVING.image();
		myLoc = new Point2D.Double();
		MainController.gameEngine.addAlienCount();

		respawnCountForTimer = 0;
		setType(i);
	}
	
	public Alien(double x, double y) {
		this(new Point((int) x, (int) y), r.nextInt(5));
	}
	
	public void updateImage(){
		Player p = MainController.gameEngine.findClosestPlayer(this);
		if (p.getX() > this.x - 3 && p.getX() < this.x + 3)
			gi = attacking[type.getNum()];
		else
			gi = moving[type.getNum()];
		if(state == Entity.State.DYING)
			gi = dying[type.getNum()];
	}

	@Override
	public void update(long timeElapsed) {
		checkForPlayer();
		if (this.state == Entity.State.SLEEPING)canWakeUpMethod(timeElapsed);
		else if (this.state == Entity.State.NORMAL) {
			// Changes images
			Player p = MainController.gameEngine.findClosestPlayer(this);
			
			// Checks if its in the air
			if (!isOnGround()) {
				setVelocityY(getVelocityY() + GRAVITY * timeElapsed
						/ 1000000000);
			}

			// Sets the dx for the alien
			if (p.getX() < this.x)
				setVelocityX(getVelocityX() - 2f * timeElapsed / 1000000000);
			else
				setVelocityX(getVelocityX() + 2f * timeElapsed / 1000000000);

			// Jumps, cast or does nothing
			double i = r.nextDouble();
			if (i < .0001)
				jump();
			if (canCast(timeElapsed))
				cast();

			// If they are trying to move left or right and are stuck, then jump
			if (Math.abs(dx) < .2)
				jump();
		}

		super.update(timeElapsed);
	}

	private void canWakeUpMethod(long timeElapsed) {
		if(respawnCountForTimer > SLEEP_TIME)wakeUp();
		else respawnCountForTimer += timeElapsed;
	}

	private boolean canCast(long timeElapsed) {
		lastCast += timeElapsed;
		return lastCast > timeToBeat;
	}

	private void newTime() {
		lastCast = 0;
		timeToBeat = (long) ((1 + r.nextDouble()) * magicCooldowns[type
				.getNum()]);
	}

	public void checkForPlayer() {
		Player p = MainController.gameEngine.findClosestPlayer(this);
		if ((p.getX() > this.x - 7 && p.getX() < this.x + 7)
				&& (p.getY() > this.y - 4 && p.getY() < this.y + 4)
				&& (this.state == Entity.State.SLEEPING)) {
			wakeUp();
		}
	}

	public void jump() {
		if (isOnGround()) {
			executeJump();
		}
	}

	private void executeJump() {
		setOnGround(false);
		setVelocityY(JUMP_SPEED);
	}

	public void cast() {
		newTime();
		Player p = MainController.gameEngine.findClosestPlayer(this);
		Point2D.Double target = p.getTarget();
		myLoc.setLocation(x, y);
		MainController.gameEngine.entities.add(new Magic(myLoc, 10, target,
				type, this, getVelocityX(), getVelocityY()));
	}

	@Override
	public void hitBy(Magic m) {
		double modifier = getModifier(m.getType());
		hit(modifier * BASE_DAMAGE);
		points = (int)(100 * modifier);
	}

	private void setType(int i) {
		if (i == 0)
			type = MagicType.AIR;
		else if (i == 1)
			type = MagicType.FIRE;
		else if (i == 2)
			type = MagicType.EARTH;
		else
			type = MagicType.WATER;
	}

	private double getModifier(MagicType type2) {
		if (type2 == MagicType.LIGHTNING) {
			return 4;
		}
		switch (type) {
		case AIR:
			return 1;
		case WATER:
			switch (type2) {
			case FIRE:
				return .5;
			case EARTH:
				return 1.5;
			case WATER:
				return 1;
			case AIR:
				return 1;
			case LIGHTNING:
				return 4;
			}
		case FIRE:
			switch (type2) {
			case FIRE:
				return 1;
			case EARTH:
				return .5;
			case WATER:
				return 1.5;
			case AIR:
				return 1;
			case LIGHTNING:
				return 4;
			}
		case EARTH:
			switch (type2) {
			case FIRE:
				return 1.5;
			case EARTH:
				return 1;
			case WATER:
				return .5;
			case AIR:
				return 1;
			case LIGHTNING:
				return 4;
			}
		}
		return 1;
	}

	public int getPoints() {
		return points;
	}

	public double getMaxSpeed() {
		return 0.05D;
	}

	@Override
	public Animation getDyingImage() {
		return dying[type.getNum()];
	}
	
	public long getRespawnCountForTimer(){
		return respawnCountForTimer;
	}
	
	public void matchWith(Alien a){
		z = a.getZ();
		x = a.getX();
		y = a.getY();
		dx = a.getVelocityX();
		dy = a.getVelocityY();
		state = a.getState();
		health = a.getHealth();
		maxHealth = a.getMaxHealth();
		
		respawnCountForTimer = a.getRespawnCountForTimer();
	}

}
